/****************************************************************
 * Fulguro
 * Copyright (C) 2004 Christophe Clienti
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 ***************************************************************/

#include "flgrCoreData.h"
#include "flgrCoreIO.h"
#include "flgrCoreCopy.h"
#include "flgrCoreDispatch.h"
#include "flgrCoreChannel.h"

/*!
 * \defgroup group_fulguro_core_channel Channel manipulation functions
 * \ingroup group_fulguro_core
 * \brief 
 * @{
 */



//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
#define FLGR_MACRO_EXTRACT1D_CHANNEL(dtype)				\
  dtype val;								\
  dtype *psrc = (dtype *) datsrc->array;				\
  dtype *pdest = (dtype *) datdest->array;				\
  int k,i;								\
  int spp = datsrc->spp;						\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  for(k=channel,i=0 ; i<datsrc->length ; i++,k+=spp) {			\
    val = flgr_get_array_##dtype(psrc,k);				\
    flgr_set_array_##dtype(pdest,i,val);				\
  }									\
									\
  return								\


void flgr1d_extract_channel_fgBIT(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT1D_CHANNEL(fgBIT);
}
void flgr1d_extract_channel_fgUINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT1D_CHANNEL(fgUINT8);
}
void flgr1d_extract_channel_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT1D_CHANNEL(fgUINT16);
}
void flgr1d_extract_channel_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT1D_CHANNEL(fgUINT32);
}
void flgr1d_extract_channel_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT1D_CHANNEL(fgINT8);
}
void flgr1d_extract_channel_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT1D_CHANNEL(fgINT16);
}
void flgr1d_extract_channel_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT1D_CHANNEL(fgINT32);
}
void flgr1d_extract_channel_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT1D_CHANNEL(fgFLOAT32);
}
void flgr1d_extract_channel_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT1D_CHANNEL(fgFLOAT64);
}
//////////////////////////////////////////////////////////////////
/*! Extract a specific channel
 *  @param datdest : destination
 *  @param datsrc : source
 *  @param channel : integer index channel ([0..spp-1])
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_extract_channel(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;
  
  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(datdest->spp != 1) {
    POST_ERROR("Destination spp != 1\n");
    return FLGR_RET_UNDEFINED_ERROR;
  }

  if((channel >= datsrc->spp) || (channel<0)) {
    POST_ERROR("Channel index not valid\n");
    return FLGR_RET_UNDEFINED_ERROR;
  }

  if((ret = flgr1d_is_data_same_length(datdest,datsrc)) != FLGR_RET_OK) return ret;
  if((ret = flgr1d_is_data_same_type(datdest,datsrc)) != FLGR_RET_OK) return ret;
 

  FLGR_DISPATCH_PROCEDURE(datdest->type, flgr1d_extract_channel, datdest,datsrc,channel);

}





//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
#define FLGR_MACRO_COMPOSE1D_CHANNEL(dtype)				\
  dtype val;								\
  dtype *psrc = (dtype *) datsrc->array;				\
  dtype *pdest = (dtype *) datdest->array;				\
  int k,i;								\
  int spp = datdest->spp;						\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  for(k=channel,i=0 ; i<datsrc->length ; i++,k+=spp) {			\
    val = flgr_get_array_##dtype(psrc,i);				\
    flgr_set_array_##dtype(pdest,k,val);				\
  }									\
									\
  return								\


void flgr1d_compose_channel_fgBIT(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE1D_CHANNEL(fgBIT);
}
void flgr1d_compose_channel_fgUINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE1D_CHANNEL(fgUINT8);
}
void flgr1d_compose_channel_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE1D_CHANNEL(fgUINT16);
}
void flgr1d_compose_channel_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE1D_CHANNEL(fgUINT32);
}
void flgr1d_compose_channel_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE1D_CHANNEL(fgINT8);
}
void flgr1d_compose_channel_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE1D_CHANNEL(fgINT16);
}
void flgr1d_compose_channel_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE1D_CHANNEL(fgINT32);
}
void flgr1d_compose_channel_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE1D_CHANNEL(fgFLOAT32);
}
void flgr1d_compose_channel_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE1D_CHANNEL(fgFLOAT64);
}
//////////////////////////////////////////////////////////////////
/*! Copy source to a specific channel in the destination
 *  @param datdest : destination
 *  @param datsrc : source
 *  @param channel : integer index channel ([0..spp-1])
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_compose_channel(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int channel) {
  FLGR_Ret ret;
  
  FLGR_DECLARE_FUNCTION;
  
  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(datsrc->spp != 1) {
    POST_ERROR("Source spp != 1\n");
    return FLGR_RET_UNDEFINED_ERROR;
  }

  if((channel >= datdest->spp) || (channel<0)) {
    POST_ERROR("Channel index not valid\n");
    return FLGR_RET_UNDEFINED_ERROR;
  }

  if((ret = flgr1d_is_data_same_length(datdest,datsrc)) != FLGR_RET_OK) return ret;
  if((ret = flgr1d_is_data_same_type(datdest,datsrc)) != FLGR_RET_OK) return ret;
 

  FLGR_DISPATCH_PROCEDURE(datdest->type, flgr1d_compose_channel, datdest,datsrc,channel);

}


//////////////////////////////////////////////////////////////////
/*! Pack all channel in a scalar pixels image (works in-place)
 *  @param dat : FLGR_Data1D
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_pack_channel(FLGR_Data1D *dat) {
  FLGR_DECLARE_FUNCTION;
  
  if((dat==NULL)) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  dat->length *= dat->spp;
  dat->spp=1;

  return FLGR_RET_OK;
}





//////////////////////////////////////////////////////////////////
/*! Unpack a scalar image in a vector image
 *  @param factor : how many channel do you want
 *  @param dat : FLGR_Data1D
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_unpack_channel(FLGR_Data1D *dat, int factor) {
  FLGR_DECLARE_FUNCTION;
  
  if((dat==NULL)) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(dat->length%factor!=0) {
    POST_WARNING("Could not unpack image, factor is not a multiple of signal length");
  }

  dat->length /= factor;
  dat->spp=factor;

  return FLGR_RET_OK;

}



/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#define FLGR_MACRO_REVERT_CHANNEL_1D(dtype)				\
  dtype val;								\
  dtype *psrc = (dtype *) datsrc->array;				\
  dtype *pdest = (dtype *) datdest->array;				\
  int l,k,j;								\
  int spp = datdest->spp;						\
  int length = datdest->spp*datdest->length;				\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  for(j=0 ; j<length ; j+=spp) {					\
    for(k=0,l=spp-1;k<spp;k++,l--) {					\
      val = flgr_get_array_##dtype(psrc,j+k);				\
      flgr_set_array_##dtype(pdest,j+l,val);				\
     }									\
  }									\
									\
  return


void flgr1d_revert_channel_fgBIT(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_1D(fgBIT);
}
void flgr1d_revert_channel_fgUINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_1D(fgUINT8);
}
void flgr1d_revert_channel_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_1D(fgUINT16);
}
void flgr1d_revert_channel_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_1D(fgUINT32);
}
void flgr1d_revert_channel_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_1D(fgINT8);
}
void flgr1d_revert_channel_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_1D(fgINT16);
}
void flgr1d_revert_channel_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_1D(fgINT32);
}
void flgr1d_revert_channel_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_1D(fgFLOAT32);
}
void flgr1d_revert_channel_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_1D(fgFLOAT64);
}



//////////////////////////////////////////////////////////////////
/*! Revert channel order
 *  @param datdest : destination
 *  @param datsrc : source
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_revert_channel(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_Ret ret;
  
  FLGR_DECLARE_FUNCTION;
  
  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret = flgr1d_is_data_same_attributes(datdest,datsrc,__FUNCTION__)) != FLGR_RET_OK) return ret;
 

  FLGR_DISPATCH_PROCEDURE(datdest->type, flgr1d_revert_channel, datdest,datsrc);
}




/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#define FLGR_MACRO_MEAN_CHANNEL_1D(dtype,dtype2)			\
  dtype2 val;								\
  dtype *psrc = (dtype *) datsrc->array;				\
  dtype *pdest = (dtype *) datdest->array;				\
  int l,k,j;								\
  int spp = datsrc->spp;						\
  int length = spp*datsrc->length;					\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  for(j=0,l=0 ; j<length ; j+=spp,l++) {				\
    val = 0;								\
    for(k=0 ; k<spp ; k++) {						\
      val += flgr_get_array_##dtype(psrc,j+k);				\
    }									\
    									\
    flgr_set_array_##dtype(pdest,l,(dtype) (val / ((dtype2)spp)) );	\
  }									\
									\
  return


void flgr1d_mean_channel_fgBIT(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_1D(fgBIT,fgUINT32);
}
void flgr1d_mean_channel_fgUINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_1D(fgUINT8,fgUINT32);
}
void flgr1d_mean_channel_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_1D(fgUINT16,fgUINT32);
}
void flgr1d_mean_channel_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_1D(fgUINT32,fgUINT64);
}
void flgr1d_mean_channel_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_1D(fgINT8,fgINT32);
}
void flgr1d_mean_channel_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_1D(fgINT16,fgINT32);
}
void flgr1d_mean_channel_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_1D(fgINT32,fgINT64);
}
void flgr1d_mean_channel_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_1D(fgFLOAT32,fgFLOAT32);
}
void flgr1d_mean_channel_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_1D(fgFLOAT64,fgFLOAT32);
}



//////////////////////////////////////////////////////////////////
/*! Get mean of channels
 *  @param datdest : destination
 *  @param datsrc : source
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_mean_channel(FLGR_Data1D *datdest, FLGR_Data1D *datsrc) {
  FLGR_Ret ret;
  
  FLGR_DECLARE_FUNCTION;
  
  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(datdest->spp != 1) {
    POST_ERROR("Destination spp != 1\n");
    return FLGR_RET_UNDEFINED_ERROR;
  }

  if((ret = flgr1d_is_data_same_type(datdest,datsrc)) != FLGR_RET_OK) return ret;
  if((ret = flgr1d_is_data_same_length(datdest,datsrc)) != FLGR_RET_OK) return ret;
 

  FLGR_DISPATCH_PROCEDURE(datdest->type, flgr1d_mean_channel, datdest,datsrc);
}










/****************************************** 2D ********************************************/

//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
#define FLGR_MACRO_EXTRACT2D_CHANNEL(dtype)				\
  FLGR_Data1D **psrc  = datsrc->row;					\
  FLGR_Data1D **pdest = datdest->row;					\
  int i;								\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  for(i=0 ; i<datsrc->size_y ; i++,pdest++,psrc++) {			\
    flgr1d_extract_channel_##dtype(*pdest,*psrc,channel);		\
  }									\
									\
  return								\


void flgr2d_extract_channel_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT2D_CHANNEL(fgBIT);
}
void flgr2d_extract_channel_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT2D_CHANNEL(fgUINT8);
}
void flgr2d_extract_channel_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT2D_CHANNEL(fgUINT16);
}
void flgr2d_extract_channel_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT2D_CHANNEL(fgUINT32);
}
void flgr2d_extract_channel_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT2D_CHANNEL(fgINT8);
}
void flgr2d_extract_channel_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT2D_CHANNEL(fgINT16);
}
void flgr2d_extract_channel_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT2D_CHANNEL(fgINT32);
}
void flgr2d_extract_channel_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT2D_CHANNEL(fgFLOAT32);
}
void flgr2d_extract_channel_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_EXTRACT2D_CHANNEL(fgFLOAT64);
}
//////////////////////////////////////////////////////////////////
/*! Extract a specific channel
 *  @param datdest : destination
 *  @param datsrc : source
 *  @param channel : integer index channel ([0..spp-1])
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_extract_channel(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;
  
  
  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(datdest->spp != 1) {
    POST_ERROR("Destination spp != 1\n");
    return FLGR_RET_UNDEFINED_ERROR;
  }

  if((channel >= datsrc->spp) || (channel<0)) {
    POST_ERROR("Channel index not valid\n");
    return FLGR_RET_UNDEFINED_ERROR;
  }

  if((ret = flgr2d_is_data_same_size(datdest,datsrc)) != FLGR_RET_OK) return ret;
  if((ret = flgr2d_is_data_same_type(datdest,datsrc)) != FLGR_RET_OK) return ret;
 

  FLGR_DISPATCH_PROCEDURE(datdest->type, flgr2d_extract_channel, datdest,datsrc,channel);

}





//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
#define FLGR_MACRO_COMPOSE2D_CHANNEL(dtype)				\
  FLGR_Data1D **psrc  = datsrc->row;					\
  FLGR_Data1D **pdest = datdest->row;					\
  int i;								\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  for(i=0 ; i<datsrc->size_y ; i++,pdest++,psrc++) {			\
    flgr1d_compose_channel_##dtype(*pdest,*psrc,channel);		\
  }									\
									\
  return								\


void flgr2d_compose_channel_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE2D_CHANNEL(fgBIT);
}
void flgr2d_compose_channel_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE2D_CHANNEL(fgUINT8);
}
void flgr2d_compose_channel_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE2D_CHANNEL(fgUINT16);
}
void flgr2d_compose_channel_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE2D_CHANNEL(fgUINT32);
}
void flgr2d_compose_channel_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE2D_CHANNEL(fgINT8);
}
void flgr2d_compose_channel_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE2D_CHANNEL(fgINT16);
}
void flgr2d_compose_channel_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE2D_CHANNEL(fgINT32);
}
void flgr2d_compose_channel_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE2D_CHANNEL(fgFLOAT32);
}
void flgr2d_compose_channel_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_MACRO_COMPOSE2D_CHANNEL(fgFLOAT64);
}
//////////////////////////////////////////////////////////////////
/*! Compose a specific channel
 *  @param datdest : destination
 *  @param datsrc : source
 *  @param channel : integer index channel ([0..spp-1])
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_compose_channel(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int channel) {
  FLGR_Ret ret;
  
  FLGR_DECLARE_FUNCTION;
  
  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(datsrc->spp != 1) {
    POST_ERROR("Source spp != 1\n");
    return FLGR_RET_UNDEFINED_ERROR;
  }

  if((channel >= datdest->spp) || (channel<0)) {
    POST_ERROR("Channel index not valid\n");
    return FLGR_RET_UNDEFINED_ERROR;
  }

  if((ret = flgr2d_is_data_same_size(datdest,datsrc)) != FLGR_RET_OK) return ret;
  if((ret = flgr2d_is_data_same_type(datdest,datsrc)) != FLGR_RET_OK) return ret;
 

  FLGR_DISPATCH_PROCEDURE(datdest->type, flgr2d_compose_channel, datdest,datsrc,channel);

}







//////////////////////////////////////////////////////////////////
/*! Pack all channel in a scalar pixels image (works in-place)
 *  @param dat : FLGR_Data2D
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_pack_channel(FLGR_Data2D *dat) {
  FLGR_Data1D **pdat;
  int i;

  FLGR_DECLARE_FUNCTION;
  
  if((dat==NULL)) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  dat->size_x *= dat->spp;
  dat->spp=1;

  for(i=0,pdat = dat->row ; i<dat->size_y ; i++, pdat++) {
    flgr1d_pack_channel(*pdat);
  }

  return FLGR_RET_OK;
}





//////////////////////////////////////////////////////////////////
/*! Unpack a scalar image in a vector image
 *  @param factor : how many channel do you want
 *  @param dat : FLGR_Data2D
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_unpack_channel(FLGR_Data2D *dat, int factor) {
  FLGR_Data1D **pdat;
  int i;

  FLGR_DECLARE_FUNCTION;
  
  if((dat==NULL)) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(dat->size_x%factor!=0) {
    POST_WARNING("Could not unpack image, factor is not a multiple of signal length");
  }

  dat->size_x /= factor;
  dat->spp=factor;

  for(i=0,pdat = dat->row ; i<dat->size_y ; i++, pdat++) {
    flgr1d_unpack_channel(*pdat, factor);
  }

  return FLGR_RET_OK;

}



//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
#define FLGR_MACRO_REVERT_CHANNEL_2D(dtype)				\
  FLGR_Data1D **psrc  = datsrc->row;					\
  FLGR_Data1D **pdest = datdest->row;					\
  int i;								\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  for(i=0 ; i<datsrc->size_y ; i++,pdest++,psrc++) {			\
    flgr1d_revert_channel_##dtype(*pdest,*psrc);			\
  }									\
									\
  return								\


void flgr2d_revert_channel_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_2D(fgBIT);
}
void flgr2d_revert_channel_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_2D(fgUINT8);
}
void flgr2d_revert_channel_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_2D(fgUINT16);
}
void flgr2d_revert_channel_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_2D(fgUINT32);
}
void flgr2d_revert_channel_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_2D(fgINT8);
}
void flgr2d_revert_channel_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_2D(fgINT16);
}
void flgr2d_revert_channel_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_2D(fgINT32);
}
void flgr2d_revert_channel_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_2D(fgFLOAT32);
}
void flgr2d_revert_channel_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_REVERT_CHANNEL_2D(fgFLOAT64);
}
//////////////////////////////////////////////////////////////////
/*! Revert channel order
 *  @param datdest : destination
 *  @param datsrc : source
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_revert_channel(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_Ret ret;
  
  FLGR_DECLARE_FUNCTION;
  
  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret = flgr2d_is_data_same_attributes(datdest,datsrc,__FUNCTION__)) != FLGR_RET_OK) return ret;

  FLGR_DISPATCH_PROCEDURE(datdest->type, flgr2d_revert_channel, datdest,datsrc);

}


//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
#define FLGR_MACRO_REVERT_CHANNEL_HMORPH_2D(dtype)			\
  FLGR_Data1D **psrc  = dat->row;					\
  FLGR_Data1D **pdest = dat->row;					\
  FLGR_Data1D *ptmp = flgr1d_create_signal_from(*psrc);			\
  int i;								\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  for(i=0 ; i<dat->size_y ; i++,pdest++,psrc++) {			\
    flgr1d_revert_channel_##dtype(ptmp,*psrc);				\
    flgr1d_copy_##dtype##_##dtype(*pdest,ptmp);				\
  }									\
									\
  flgr1d_destroy(ptmp);							\
  return								\


void flgr2d_revert_channel_hmorph_fgBIT(FLGR_Data2D *dat) {
  FLGR_MACRO_REVERT_CHANNEL_HMORPH_2D(fgBIT);
}
void flgr2d_revert_channel_hmorph_fgUINT8(FLGR_Data2D *dat) {
  FLGR_MACRO_REVERT_CHANNEL_HMORPH_2D(fgUINT8);
}
void flgr2d_revert_channel_hmorph_fgUINT16(FLGR_Data2D *dat) {
  FLGR_MACRO_REVERT_CHANNEL_HMORPH_2D(fgUINT16);
}
void flgr2d_revert_channel_hmorph_fgUINT32(FLGR_Data2D *dat) {
  FLGR_MACRO_REVERT_CHANNEL_HMORPH_2D(fgUINT32);
}
void flgr2d_revert_channel_hmorph_fgINT8(FLGR_Data2D *dat) {
  FLGR_MACRO_REVERT_CHANNEL_HMORPH_2D(fgINT8);
}
void flgr2d_revert_channel_hmorph_fgINT16(FLGR_Data2D *dat) {
  FLGR_MACRO_REVERT_CHANNEL_HMORPH_2D(fgINT16);
}
void flgr2d_revert_channel_hmorph_fgINT32(FLGR_Data2D *dat) {
  FLGR_MACRO_REVERT_CHANNEL_HMORPH_2D(fgINT32);
}
void flgr2d_revert_channel_hmorph_fgFLOAT32(FLGR_Data2D *dat) {
  FLGR_MACRO_REVERT_CHANNEL_HMORPH_2D(fgFLOAT32);
}
void flgr2d_revert_channel_hmorph_fgFLOAT64(FLGR_Data2D *dat) {
  FLGR_MACRO_REVERT_CHANNEL_HMORPH_2D(fgFLOAT64);
}
//////////////////////////////////////////////////////////////////
/*! Revert channel order inplace
 *  @param dat 
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_revert_channel_hmorph(FLGR_Data2D *dat) {
  FLGR_DECLARE_FUNCTION;
  
  if(dat==NULL) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  FLGR_DISPATCH_PROCEDURE(dat->type, flgr2d_revert_channel_hmorph, dat);

}





//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
#define FLGR_MACRO_MEAN_CHANNEL_2D(dtype)				\
  FLGR_Data1D **psrc  = datsrc->row;					\
  FLGR_Data1D **pdest = datdest->row;					\
  int i;								\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  for(i=0 ; i<datsrc->size_y ; i++,pdest++,psrc++) {			\
    flgr1d_mean_channel_##dtype(*pdest,*psrc);				\
  }									\
									\
  return


void flgr2d_mean_channel_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_2D(fgBIT);
}
void flgr2d_mean_channel_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_2D(fgUINT8);
}
void flgr2d_mean_channel_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_2D(fgUINT16);
}
void flgr2d_mean_channel_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_2D(fgUINT32);
}
void flgr2d_mean_channel_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_2D(fgINT8);
}
void flgr2d_mean_channel_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_2D(fgINT16);
}
void flgr2d_mean_channel_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_2D(fgINT32);
}
void flgr2d_mean_channel_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_2D(fgFLOAT32);
}
void flgr2d_mean_channel_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_MEAN_CHANNEL_2D(fgFLOAT64);
}



//////////////////////////////////////////////////////////////////
/*! Get mean of channels
 *  @param datdest : destination
 *  @param datsrc : source
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_mean_channel(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_Ret ret;
  
  FLGR_DECLARE_FUNCTION;
  
  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(datdest->spp != 1) {
    POST_ERROR("Destination spp != 1\n");
    return FLGR_RET_UNDEFINED_ERROR;
  }

  if((ret = flgr2d_is_data_same_type(datdest,datsrc)) != FLGR_RET_OK) return ret;
  if((ret = flgr2d_is_data_same_size(datdest,datsrc)) != FLGR_RET_OK) return ret;
 

  FLGR_DISPATCH_PROCEDURE(datdest->type, flgr2d_mean_channel, datdest,datsrc);
}
//! @}

